package com.lazybones.base.engineer.utils.google;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.UndeclaredThrowableException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;

public class VerifyNumUtils {


    public VerifyNumUtils() {
    }
    // 0 1 2 3 4 5 6 7 8
    private static final int[] DIGITS_POWER = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
/**
 *该方法使用JCE来提供加密算法。HMAC计算
 *使用加密哈希算法作为的哈希消息身份验证代码
 参数
 *@param crypto:加密算法（HmacSHA1、HmacSHA256、HmacSHA512）
 *@param keyBytes：用于HMAC密钥的字节
 *@param text:要验证的消息或文本
 */
private static byte[] hmacSha(String crypto, byte[] keyBytes, byte[] text) {
        try {
            Mac hmac;
            hmac = Mac.getInstance(crypto);
            SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
            hmac.init(macKey);
            return hmac.doFinal(text);
        } catch (GeneralSecurityException gse) {
            throw new UndeclaredThrowableException(gse);
        }
    }
    private static byte[] hexStr2Bytes(String hex) {
        byte[] bArray = new BigInteger("10" + hex, 16).toByteArray();
        byte[] ret = new byte[bArray.length - 1];
        System.arraycopy(bArray, 1, ret, 0, ret.length);
        return ret;
    }

    public static String generateVerify512(String key, String time,
                                         String returnDigits) {
        return generateVerify(key, time, returnDigits, "HmacSHA512");
    }
    public static String generateVerify256(String key, String time,
                                         String returnDigits) {
        return generateVerify(key, time, returnDigits, "HmacSHA256");
    }
    public static String generateVerify(String key, String time,
                                      String returnDigits) {
        return generateVerify(key, time, returnDigits, "HmacSHA1");
    }


    public static String generateVerify(String key,String time,String returnDigits,String crypto){
        int codeDigits = Integer.decode(returnDigits);
        StringBuilder timeBuilder = new StringBuilder(time);
        while (timeBuilder.length() < 16) {
            // time = "0" + time;
            timeBuilder.insert(0, "0");
        }
        time = timeBuilder.toString();
        byte[] msg = hexStr2Bytes(time);
        byte[] k = hexStr2Bytes(key);
        byte[] hash = hmacSha(crypto, k, msg);
        int offset = hash[hash.length - 1] & 0xf;
        int binary = ((hash[offset] & 0x7f) << 24)
                | ((hash[offset + 1] & 0xff) << 16)
                | ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff);
        int otp = binary % DIGITS_POWER[codeDigits];
        String result = Integer.toString(otp);
        while (result.length() < codeDigits) {
            result = "0" + result;
        }
        return result;

    }

}
